AUTHENTICATION METHODS FOR ASP.NET CORE WEB API

1. JWT (JSON Web Token) Authentication

Most common for SPAs (like your React frontend)

  • βœ… Stateless: No session stored on the server.
  • πŸ” Token structure: Header + Payload (including roles) + Signature.
  • 🎯 Good for: SPAs, mobile apps, APIs.
  • πŸ“¦ Libraries: Microsoft.AspNetCore.Authentication.JwtBearer.

Setup Highlights:

  • Client sends credentials β†’ API generates token with user roles β†’ Client stores token β†’ Client sends token in Authorization header (Bearer <token>).
  • Server verifies signature and extracts user identity and roles from the token.

Role support:

  • You embed roles inside the JWT ("roles": ["Admin", "User"]).
  • Use [Authorize(Roles = "Admin")].

2. Cookie-Based Authentication

Traditional approach for server-rendered apps (not ideal for APIs)

  • πŸ›‘ Not recommended for APIs due to CSRF vulnerability and session overhead.
  • πŸ—‚ Stores session identifier in browser cookie.
  • Useful when using ASP.NET Core MVC or Razor Pages (not Web API).

3. OAuth2 + OpenID Connect (OIDC)

Best for federated login, single sign-on (SSO), or external providers

  • πŸ”— Integrates with Identity Providers (IDPs) like:
    • Azure AD
    • Google, Facebook, GitHub
    • Auth0, Okta, Duende IdentityServer
  • πŸ“¦ Library: Microsoft.AspNetCore.Authentication.OpenIdConnect
  • Uses access tokens (JWT) issued by an authority.

Role support:

  • Roles/claims provided by the Identity Provider.
  • You map these claims to roles in the API.
  • [Authorize(Roles = "Admin")] still works.

4. API Key Authentication

Lightweight alternative (not ideal for user-based roles)

  • Client includes a static API key in headers or query string.
  • πŸ” No user context β†’ ❌ no role-based support unless you map API keys to roles in a custom way.
  • πŸ”§ Implemented manually in middleware or filters.

5. Basic Authentication

  • User provides username:password in Base64 via Authorization header.
  • ❌ Insecure unless used with HTTPS.
  • ⚠️ Rarely used anymore β€” not good for role-based systems or production apps.

6. ASP.NET Core Identity

Full-featured user management system (often combined with JWT)

  • βœ… Provides login, registration, role management, password hashing, etc.
  • 🎯 Good choice if you want to own the user system and manage roles yourself.
  • Can be used with:
    • JWT tokens (custom token generation)
    • Cookie auth (not for APIs)
  • πŸ”§ Use UserManager, RoleManager.

Example: Use Identity for creating users and roles, then issue JWTs on login.


Summary Table

Method Stateless Token-Based Role Support Ideal For
JWT Authentication βœ… βœ… βœ… APIs, SPAs (React, etc.)
Cookie Authentication ❌ ❌ βœ… Server-side apps only
OAuth2 + OpenID Connect βœ… βœ… βœ… External login, SSO, enterprise
API Key βœ… ❌ ❌ (manual) Simple apps, service-to-service
Basic Auth βœ… ❌ ❌ (manual) Very basic use, not recommended
ASP.NET Core Identity ❌ Optional βœ… User/Role management

Web Security and JWT Terms

🧨 CSP (Content Security Policy)

Definition:
A browser security mechanism that helps prevent XSS attacks by controlling which sources the browser can load content from.

Example Usage:
It can prevent JavaScript from running unless it's from a trusted source.

Example CSP header:

Content-Security-Policy: default-src 'self'; script-src 'self' https://trustedscripts.example.com

πŸ’₯ XSS (Cross-Site Scripting)

Definition:
A vulnerability where an attacker injects malicious JavaScript into a web page that gets executed in a user’s browser.

Why It Matters for JWT:
If you store JWTs in localStorage, and your app is vulnerable to XSS, the attacker can steal the token and impersonate the user.

Prevention:

  • Never trust user input (sanitize!)
  • Use CSP headers
  • Avoid inline scripts
  • Use frameworks that auto-escape HTML (like React, Razor)

πŸ“¦ Payload (in JWT)

Definition:
The middle part of a JWT. It contains the claims (user data, permissions, roles, etc.) in a Base64-encoded JSON format.

Example:

{
  "sub": "1234567890",
  "name": "John Doe",
  "role": "Admin",
  "exp": 1716850984
}

⚠️ Note: Payload is not encrypted, just encoded β€” anyone can read it, but not modify it without invalidating the signature.


✍️ Signature (in JWT)

Definition:
The third part of the token. It's a cryptographic hash (HMAC or RSA/ECDSA) of the header and payload, signed with a secret or private key.

Purpose:
To verify that the token hasn’t been tampered with.

Structure:

JWT = base64(header) + '.' + base64(payload) + '.' + signature

Only the server (with the secret key) can validate the signature.


🦠 CSRF (Cross-Site Request Forgery)

Definition:
A vulnerability where an attacker tricks a user’s browser (with a valid session/cookie) into making an unwanted request to your site without the user’s knowledge.

Example:
If you're logged in and visit a malicious site, that site may submit a POST request using your cookies to perform actions on your behalf.

Why It Matters:

  • If you store JWTs in HttpOnly cookies, you must guard against CSRF.

Defense:

  • Use SameSite=Strict cookies
  • Use anti-CSRF tokens
  • Prefer Authorization header with tokens (doesn’t auto-send like cookies)

🧠 Session Overhead

Definition:
The memory and server resource cost of maintaining a session for each logged-in user on the server.

Why It Matters:

  • Traditional cookie-based auth stores session info on the server.
  • With JWT, the session is stateless (no server memory), reducing overhead and scaling better.

πŸ”‘ Authentication Ecosystem Concepts


🌐 Federated Login

Definition:
Users log in to your application using another trusted identity provider (IdP), such as:

  • Google
  • Facebook
  • Microsoft
  • GitHub

You delegate authentication to the third party and just receive user info (often as a JWT or OpenID Connect token).

Protocol Examples:

  • OAuth2
  • OpenID Connect

πŸ” SSO (Single Sign-On)

Definition:
A user logs in once and gains access to multiple systems or applications without logging in again.

Common in Enterprises:

  • Logging into one dashboard gives you access to HR system, email, file storage, etc.

How It Works:

  • A central identity provider (IdP) issues tokens
  • Applications trust the token and skip login
  • Often uses OAuth2, OpenID Connect, or SAML

πŸ”„ Summary Table

Term Meaning
CSP Restricts sources of scripts/styles to prevent XSS
XSS Injected JavaScript that steals data like JWT tokens
JWT Payload JSON with user claims (readable but not secure on its own)
JWT Signature Proves the token is untampered (signed by server)
CSRF Unauthorized actions using authenticated user's browser/session
Session Overhead Cost of storing user sessions in memory on the server
Federated Login Login using a third-party identity provider (e.g., Google)
SSO One login grants access to multiple trusted systems

ASP.NET Identity vs JWT Authentication


βœ… What is ASP.NET Identity?

ASP.NET Identity is a full membership system that:

  • Manages users, roles, passwords, claims, tokens, and external logins.
  • Stores user data in a database (usually using Entity Framework).
  • Works well with cookie-based authentication by default.
  • Handles login, logout, registration, password hashing, email confirmation, two-factor auth, etc.

Default storage: SQL Server (via Entity Framework)


πŸ”‘ How Authentication Works in ASP.NET Identity (Cookie-Based)

  1. Login request: The user submits a form with username/password.
  2. Server validates the credentials using ASP.NET Identity.
  3. If valid, the server issues a cookie (with a session token).
  4. The browser stores this authentication cookie.
  5. For future requests, the browser automatically sends the cookie.
  6. The server validates the cookie (and reads the user session from memory or database).

βœ… Stateful
❌ Doesn't scale well for large APIs unless you add external session storage (like Redis).


πŸ” What is JWT Authentication?

JWT Authentication is:

  • Stateless.
  • Based on tokens β€” not sessions.
  • Works well for APIs and SPAs/mobile apps.

Flow:

  1. User logs in, and if credentials are valid...
  2. Server creates a JWT containing user info (e.g., roles).
  3. Server signs the token and sends it to the client.
  4. Client stores it (e.g., in localStorage or cookies).
  5. On every request, the client sends the JWT in the Authorization header.
  6. Server verifies the JWT signature using a secret or key.
  7. If valid β†’ allow access (no server-side session needed).

βœ… Stateless
βœ… Scales easily
βœ… Good for distributed APIs


πŸ“Š Comparison Table

Feature ASP.NET Identity (Cookie) JWT Authentication (Token-Based)
Stateful/Stateless Stateful Stateless
Storage Cookie on client, session on server Token on client only
Default Transport Cookie (auto-sent by browser) Authorization header (manual send)
Built-in Support ASP.NET Identity (UI + EF Core) ASP.NET Core + Manual JWT setup
Scalability Limited (server stores session) High (no session to manage)
Security Cookie CSRF risk XSS risk if stored in JS-accessible storage
Use Case Web apps with UI (MVC, Razor) APIs, SPAs, mobile apps
External login support Built-in Needs integration
Token expiration Server-controlled session Token has expiration embedded

🚨 Statelessness β€” What Does It Mean?

  • Stateful Authentication: Server stores a session (usually in memory or a database) for each user. The client just stores a cookie with a session ID.
    • When user logs in, server keeps a record of that.
    • Logout β†’ delete session.
  • Stateless Authentication (JWT):
    • Server does not remember anything.
    • JWT has all info about the user in itself (claims, roles, expiry).
    • Logout = just delete token on client side (server has no "memory").

⚠️ You can't "force logout" someone server-side in pure JWT unless you blacklist tokens manually (or rotate secrets).


πŸ’‘ Can You Use ASP.NET Identity with JWT?

Yes β€” ASP.NET Identity can be configured to:

  • Authenticate user credentials
  • Then issue a JWT instead of using a cookie
  • This way, you get:
    • ASP.NET Identity’s user management
    • JWT’s stateless API authentication

This is often used in hybrid apps:

  • Use Identity for registration/login
  • Use JWT for frontend and mobile API calls

What does null! mean?

It's a null-forgiving operator.

When you write:

string? maybeNull = null;
string definitelyNotNull = null!;  // ← This tells the compiler: β€œTrust me, it’s not null.”

You're telling the compiler:

β€œI know this is technically null, but treat it as non-null and don’t warn me.”


🧩 Why is this needed?

C# 8 introduced nullable reference types, where the compiler gives warnings if you assign or use null where it's not safe.

For example:

string name = null; // Warning: assigning null to non-nullable reference

To silence the warning, you can use null!:

string name = null!; // No warning

But this is your responsibility: the compiler assumes you're guaranteeing that it won’t cause a NullReferenceException.


⚠️ When to use null!?

Use it sparingly and carefully, only when:

  • You know an object will be initialized later.
  • You’re working with ORMs like EF Core where properties are set after construction.
  • You're dealing with dependency injection and the value is assigned automatically later.

Example:

public class Account
{
    public string PhoneNumber { get; set; } = null!; // EF will populate it
}

βœ… Summary

Expression Meaning
null! "This is null, but treat it as if it's non-null (trust me)."
Use case Avoiding compiler warnings for nullable reference types
Risk Can lead to runtime NullReferenceException if used incorrectly

Let me know if you want help turning on/off nullable reference types or dealing with EF Core model warnings.

What is a JWT Generator?

A JWT Generator is a class or service in your backend that:

  1. Generates a signed JWT (JSON Web Token) when a user logs in.
  2. Encodes the user's identity, roles, and other claims.
  3. Signs the token with a secret or private key so it can be validated later.

πŸ”§ Structure of a JWT

A JWT has 3 parts:

xxxxx.yyyyy.zzzzz
  1. Header (Base64-encoded JSON):

    {
      "alg": "HS256",
      "typ": "JWT"
    }
    
  2. Payload (Base64-encoded JSON):
    Contains user data and claims (e.g., user ID, role, expiry).

    {
      "sub": "userId123",
      "phone": "0930xxx",
      "role": "Admin",
      "exp": 1717502800
    }
    
  3. Signature:
    HMACSHA256(header + "." + payload, secret key)


βœ… What Goes into the Payload?

Include things you want to check without querying the DB every time:

  • sub (Subject – usually user ID)
  • phone or username
  • role (e.g., "Admin", "User")
  • exp (expiration timestamp)
  • Any custom claim, like companyId, verified, etc.

πŸ” Signature

The signature ensures that the token hasn't been tampered with. If the signature doesn't match (due to modification or incorrect secret), the token is invalid.


🧱 Example: JWT Generator in ASP.NET Core

public interface IJwtGenerator
{
    string GenerateToken(Account account);
}
public class JwtGenerator : IJwtGenerator
{
    private readonly IConfiguration _config;

    public JwtGenerator(IConfiguration config)
    {
        _config = config;
    }

    public string GenerateToken(Account account)
    {
        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, account.Id.ToString()),
            new Claim(JwtRegisteredClaimNames.PhoneNumber, account.PhoneNumber),
            new Claim(ClaimTypes.Role, account.Role),
        };

        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]!));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var token = new JwtSecurityToken(
            issuer: _config["Jwt:Issuer"],
            audience: _config["Jwt:Audience"],
            claims: claims,
            expires: DateTime.UtcNow.AddHours(2),
            signingCredentials: creds
        );

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

πŸ›  Configuration in appsettings.json

"Jwt": {
  "Key": "YourSuperSecureSecretKey123!",
  "Issuer": "YourAppName",
  "Audience": "YourFrontendApp"
}

πŸ§ͺ Token Validation

When the frontend sends this token on requests (via Authorization: Bearer <token> header), ASP.NET Core automatically validates:

  • Signature (using the same secret)
  • Expiry (exp)
  • Audience, Issuer
  • Claims (like role)

This is done via JwtBearer middleware.


πŸ” Roles in the Token?

Yes, you can (and should) include user roles. The backend will automatically enforce [Authorize(Roles = "Admin")] using that claim.

But:

  • Don't rely only on frontend logic β€” always protect endpoints on the backend too.
  • Frontend can use roles to hide UI elements, but not for enforcing access.

πŸ€” Should You Encrypt the Token?

No, standard practice is:

  • Don't encrypt JWTs β€” they’re just base64-encoded.
  • Don’t put sensitive data inside.
  • Sign them to prevent tampering.
  • Secure the token in frontend (e.g., HttpOnly cookies or localStorage with care).

βœ… Summary of Responsibilities

Responsibility Backend (JWT Generator) Frontend
Token generation βœ… ❌
Storing token ❌ βœ… (localStorage / cookie)
Sending token ❌ βœ… (Authorization header)
Token validation βœ… (JwtBearer) ❌
Role enforcement βœ… ([Authorize]) βœ… (UI-level only)

How multiple roles in JWT claims work

  • The JWT claims are basically a list of key-value pairs.
  • For roles, the key is usually "role" or ClaimTypes.Role.
  • You add multiple claims with the same key β€” one for each role.

Example:

{
  "sub": "1234567890",
  "phone_number": "123456789",
  "role": "Admin",
  "role": "Editor",
  "role": "User",
  "exp": 1711600000
}
  • When the token is created, it contains multiple "role" entries.
  • On the backend, ASP.NET Core ClaimsPrincipal reads all of them, so [Authorize(Roles="Admin,Editor")] works by checking if any of the roles match.

How frontend handles multiple roles in the JWT

  1. The frontend receives the JWT (usually after login).
  2. It decodes the JWT payload (using a library like jwt-decode).
  3. It extracts the roles as an array of strings.

Example in React using jwt-decode:

import jwtDecode from 'jwt-decode';

const token = localStorage.getItem('token');
const decoded = jwtDecode(token);
const roles = decoded.role; // roles is usually an array if multiple roles exist

console.log(roles); // ["Admin", "Editor", "User"]
  1. The frontend can then use these roles to:

    • Conditionally render UI components or routes.
    • Show/hide buttons, pages, or features.

Important security note for frontend roles

  • The frontend can only do UI-level checks based on roles.
  • Never trust frontend role checks to secure data or APIs.
  • The backend must always verify the token and roles via [Authorize] attributes or middleware.

Summary

Step How it works
JWT creation Multiple "role" claims added to token
Backend authorization Validates token and checks if user has required roles
Frontend decoding Extracts role claim(s) as array of strings
Frontend UI control Shows or hides content based on roles